#include "helper/terrainactiveblockhelperobject.h"
#include "terrain/terrainobject.h"
#include "terrain/terrainblock.h"
//#include "terrain/terrainsurface.h"
#include <standard/resourcemanager.h>

CTerrainActiveBlockHelperGeometry::CTerrainActiveBlockHelperGeometry(CTerrainObject* pTerrainObject){
    m_pTerrainObject = pTerrainObject;
    m_nTerrainActiveBlockHelperGeometryType = 0;
}
CTerrainActiveBlockHelperGeometry::~CTerrainActiveBlockHelperGeometry(){

}
CVertexBuffer* CTerrainActiveBlockHelperGeometry::GetRenderBuffer(){
    return m_rRenderBuffer.GetEntityData();
}
CIndexBuffer* CTerrainActiveBlockHelperGeometry::GetIndexBuffer(){
    return m_rIndexBuffer.GetEntityData();
}
void CTerrainActiveBlockHelperGeometry::UpdateGeometry( list<CTerrainBlock*>* pTerrainBlockList, int32 nBlockCoordsX, int32 nBlockCoordsY, int32 nShape, int32 nSize ){
}

bool32 CTerrainActiveBlockHelperGeometry::BuildActiveBlockGeometry( list<CTerrainBlock*>* pTerrainBlockList, int32 nCoordsX, int32 nCoordsY, vector<TV3C1T2>* pVertexList, vector<uint16>* pIndexList ){
    int32 _nIndex = pVertexList->size();
    color32 _cColor = 0x8855aa22;
    TV3C1T2 _sVert;

    int32 _nCellX = nCoordsX;
    int32 _nCellY = nCoordsY;

    float _vHeight[9];
    float __vHeight[9];

    _vHeight[0] = m_pTerrainObject->GetCellHeight( _nCellX - 1, _nCellY - 1 );
    _vHeight[1] = m_pTerrainObject->GetCellHeight( _nCellX,     _nCellY - 1 );
    _vHeight[2] = m_pTerrainObject->GetCellHeight( _nCellX + 1, _nCellY - 1 );
    _vHeight[3] = m_pTerrainObject->GetCellHeight( _nCellX - 1, _nCellY );
    _vHeight[4] = m_pTerrainObject->GetCellHeight( _nCellX,     _nCellY );
    _vHeight[5] = m_pTerrainObject->GetCellHeight( _nCellX + 1, _nCellY );
    _vHeight[6] = m_pTerrainObject->GetCellHeight( _nCellX - 1, _nCellY + 1 );
    _vHeight[7] = m_pTerrainObject->GetCellHeight( _nCellX,     _nCellY + 1 );
    _vHeight[8] = m_pTerrainObject->GetCellHeight( _nCellX + 1, _nCellY + 1 );

    __vHeight[0] = (_vHeight[0] + _vHeight[4]) * 0.5f;
    __vHeight[1] = (_vHeight[1] + _vHeight[4]) * 0.5f;
    __vHeight[2] = (_vHeight[1] + _vHeight[5]) * 0.5f;

    __vHeight[3] = (_vHeight[3] + _vHeight[4]) * 0.5f;
    __vHeight[4] = _vHeight[4];
    __vHeight[5] = (_vHeight[5] + _vHeight[4]) * 0.5f;

    __vHeight[6] = (_vHeight[3] + _vHeight[7]) * 0.5f;
    __vHeight[7] = (_vHeight[7] + _vHeight[4]) * 0.5f;
    __vHeight[8] = (_vHeight[8] + _vHeight[4]) * 0.5f;




    float _fLeftRightMid = m_pTerrainObject->m_fStartPosX + m_pTerrainObject->m_fCellSize * nCoordsX;
    float _fLeft = _fLeftRightMid - m_pTerrainObject->m_fHalfCellSize;
    float _fRight = _fLeftRightMid + m_pTerrainObject->m_fHalfCellSize;

    float _fTopBottomMid = m_pTerrainObject->m_fStartPosY + m_pTerrainObject->m_fCellSize * nCoordsY;
    float _fTop = _fTopBottomMid - m_pTerrainObject->m_fHalfCellSize;
    float _fBottom = _fTopBottomMid + m_pTerrainObject->m_fHalfCellSize;

    TV3C1T2_SETS(_sVert, _fLeft,          __vHeight[0], _fTop,             _cColor, 0.5f, 0.6f );pVertexList->push_back(_sVert);
    TV3C1T2_SETS(_sVert, _fLeft,          __vHeight[3], _fTopBottomMid,    _cColor, 0.5f, 0.6f );pVertexList->push_back(_sVert);
    TV3C1T2_SETS(_sVert, _fLeftRightMid,  __vHeight[4], _fTopBottomMid,    _cColor, 0.5f, 0.6f );pVertexList->push_back(_sVert);
    TV3C1T2_SETS(_sVert, _fLeftRightMid,  __vHeight[1], _fTop,             _cColor, 0.5f, 0.6f );pVertexList->push_back(_sVert);
    pIndexList->push_back(_nIndex);     pIndexList->push_back(_nIndex + 1 );    pIndexList->push_back(_nIndex + 2);
    pIndexList->push_back(_nIndex + 2); pIndexList->push_back(_nIndex + 3);     pIndexList->push_back(_nIndex + 0);
    _nIndex += 4;

    TV3C1T2_SETS(_sVert, _fLeftRightMid,  __vHeight[1], _fTop,             _cColor, 0.5f, 0.6f );pVertexList->push_back(_sVert);
    TV3C1T2_SETS(_sVert, _fLeftRightMid,  __vHeight[4], _fTopBottomMid,    _cColor, 0.5f, 0.6f );pVertexList->push_back(_sVert);
    TV3C1T2_SETS(_sVert, _fRight,         __vHeight[5], _fTopBottomMid,    _cColor, 0.5f, 0.6f );pVertexList->push_back(_sVert);
    TV3C1T2_SETS(_sVert, _fRight,         __vHeight[2], _fTop,             _cColor, 0.5f, 0.6f );pVertexList->push_back(_sVert);
    pIndexList->push_back(_nIndex);     pIndexList->push_back(_nIndex + 1 );    pIndexList->push_back(_nIndex + 2);
    pIndexList->push_back(_nIndex + 2); pIndexList->push_back(_nIndex + 3);     pIndexList->push_back(_nIndex + 0);
    _nIndex += 4;

    TV3C1T2_SETS(_sVert, _fLeft,          __vHeight[3], _fTopBottomMid,    _cColor, 0.5f, 0.6f );pVertexList->push_back(_sVert);
    TV3C1T2_SETS(_sVert, _fLeft,          __vHeight[6], _fBottom,          _cColor, 0.5f, 0.6f );pVertexList->push_back(_sVert);
    TV3C1T2_SETS(_sVert, _fLeftRightMid,  __vHeight[7], _fBottom,          _cColor, 0.5f, 0.6f );pVertexList->push_back(_sVert);
    TV3C1T2_SETS(_sVert, _fLeftRightMid,  __vHeight[4], _fTopBottomMid,    _cColor, 0.5f, 0.6f );pVertexList->push_back(_sVert);
    pIndexList->push_back(_nIndex);     pIndexList->push_back(_nIndex + 1 );    pIndexList->push_back(_nIndex + 2);
    pIndexList->push_back(_nIndex + 2); pIndexList->push_back(_nIndex + 3);     pIndexList->push_back(_nIndex + 0);
    _nIndex += 4;

    TV3C1T2_SETS(_sVert, _fLeftRightMid,  __vHeight[4], _fTopBottomMid,    _cColor, 0.5f, 0.6f );pVertexList->push_back(_sVert);
    TV3C1T2_SETS(_sVert, _fLeftRightMid,  __vHeight[7], _fBottom,          _cColor, 0.5f, 0.6f );pVertexList->push_back(_sVert);
    TV3C1T2_SETS(_sVert, _fRight,         __vHeight[8], _fBottom,          _cColor, 0.5f, 0.6f );pVertexList->push_back(_sVert);
    TV3C1T2_SETS(_sVert, _fRight,         __vHeight[5], _fTopBottomMid,    _cColor, 0.5f, 0.6f );pVertexList->push_back(_sVert);
    pIndexList->push_back(_nIndex);     pIndexList->push_back(_nIndex + 1 );    pIndexList->push_back(_nIndex + 2);
    pIndexList->push_back(_nIndex + 2); pIndexList->push_back(_nIndex + 3);     pIndexList->push_back(_nIndex + 0);
    _nIndex += 4;

    return True;
}


////////////////////////////////////////////////////////////////////////////////////////////////////
CTerrainBrushGeometry::CTerrainBrushGeometry(CTerrainObject* pTerrainObject) :
CTerrainActiveBlockHelperGeometry(pTerrainObject) {
    m_nTerrainActiveBlockHelperGeometryType = 0;
}
CTerrainBrushGeometry::~CTerrainBrushGeometry() {

}

void CTerrainBrushGeometry::UpdateGeometry(list<CTerrainBlock*>* pTerrainBlockList, int32 nBlockCoordsX, int32 nBlockCoordsY, int32 nShape, int32 nSize) {
    vector<TV3C1T2> _vVertex;
    vector<uint16> _vIndexData;

    vector<TV3C1T2>* _pvVertexList = &_vVertex;
    vector<uint16>* _pvIndexList = &_vIndexData;

    if (nShape == 0) {
        if (nSize == 1) {
            BuildActiveBlockGeometry(pTerrainBlockList, nBlockCoordsX, nBlockCoordsY, _pvVertexList, _pvIndexList);
        }else if (nSize == 2) {
            BuildActiveBlockGeometry(pTerrainBlockList, nBlockCoordsX, nBlockCoordsY - 1, _pvVertexList, _pvIndexList);
            BuildActiveBlockGeometry(pTerrainBlockList, nBlockCoordsX - 1, nBlockCoordsY, _pvVertexList, _pvIndexList);
            BuildActiveBlockGeometry(pTerrainBlockList, nBlockCoordsX, nBlockCoordsY, _pvVertexList, _pvIndexList);
            BuildActiveBlockGeometry(pTerrainBlockList, nBlockCoordsX + 1, nBlockCoordsY, _pvVertexList, _pvIndexList);
            BuildActiveBlockGeometry(pTerrainBlockList, nBlockCoordsX, nBlockCoordsY + 1, _pvVertexList, _pvIndexList);
        }else if (nSize == 3) {
            bool32 _bvBlockMask[5][5] = {
                { False, False, True, False, False },
                { False,  True, True,  True, False },
                {  True,  True, True,  True,  True },
                { False,  True, True,  True, False },
                { False, False, True, False, False },
            };
            int32 _nBlockStartX = nBlockCoordsX - 2;
            int32 _nBlockStartY = nBlockCoordsY - 2;
            for (int32 j = _nBlockStartY; j < _nBlockStartY + 5; j++) {
                for (int32 i = _nBlockStartX; i < _nBlockStartX + 5; i++) {
                    if (_bvBlockMask[j - _nBlockStartY][i - _nBlockStartX] == True) {
                        BuildActiveBlockGeometry(pTerrainBlockList, i, j, _pvVertexList, _pvIndexList);
                    }
                }
            }
        }else if (nSize == 5) {
            bool32 _bvBlockMask[9][9] = {
                { False, False, False, False,  True, False, False, False, False },
                { False, False,  True,  True,  True,  True,  True, False, False },
                { False,  True,  True,  True,  True,  True,  True,  True, False },
                { False,  True,  True,  True,  True,  True,  True,  True, False },
                {  True,  True,  True,  True,  True,  True,  True,  True,  True },
                { False,  True,  True,  True,  True,  True,  True,  True, False },
                { False,  True,  True,  True,  True,  True,  True,  True, False },
                { False, False,  True,  True,  True,  True,  True, False, False },
                { False, False, False, False,  True, False, False, False, False },
            };
            int32 _nBlockStartX = nBlockCoordsX - 4;
            int32 _nBlockStartY = nBlockCoordsY - 4;
            for (int32 j = _nBlockStartY; j < _nBlockStartY + 9; j++) {
                for (int32 i = _nBlockStartX; i < _nBlockStartX + 9; i++) {
                    if (_bvBlockMask[j - _nBlockStartY][i - _nBlockStartX] == True) {
                        BuildActiveBlockGeometry(pTerrainBlockList, i, j, _pvVertexList, _pvIndexList);
                    }
                }
            }
        }else if (nSize == 8) {
            bool32 _bvBlockMask[15][15] = {
                { False, False, False, False, False, False,  True,  True,  True, False, False, False, False, False, False },
                { False, False, False, False,  True,  True,  True,  True,  True,  True,  True, False, False, False, False },
                { False, False, False,  True,  True,  True,  True,  True,  True,  True,  True,  True, False, False, False },
                { False, False,  True,  True,  True,  True,  True,  True,  True,  True,  True,  True,  True, False, False },
                { False,  True,  True,  True,  True,  True,  True,  True,  True,  True,  True,  True,  True,  True, False },
                { False,  True,  True,  True,  True,  True,  True,  True,  True,  True,  True,  True,  True,  True, False },
                {  True,  True,  True,  True,  True,  True,  True,  True,  True,  True,  True,  True,  True,  True,  True },
                {  True,  True,  True,  True,  True,  True,  True,  True,  True,  True,  True,  True,  True,  True,  True },
                {  True,  True,  True,  True,  True,  True,  True,  True,  True,  True,  True,  True,  True,  True,  True },
                { False,  True,  True,  True,  True,  True,  True,  True,  True,  True,  True,  True,  True,  True, False },
                { False,  True,  True,  True,  True,  True,  True,  True,  True,  True,  True,  True,  True,  True, False },
                { False, False,  True,  True,  True,  True,  True,  True,  True,  True,  True,  True,  True, False, False },
                { False, False, False,  True,  True,  True,  True,  True,  True,  True,  True,  True, False, False, False },
                { False, False, False, False,  True,  True,  True,  True,  True,  True,  True, False, False, False, False },
                { False, False, False, False, False, False,  True,  True,  True, False, False, False, False, False, False },
            };
            int32 _nBlockStartX = nBlockCoordsX - 7;
            int32 _nBlockStartY = nBlockCoordsY - 7;
            for (int32 j = _nBlockStartY; j < _nBlockStartY + 15; j++) {
                for (int32 i = _nBlockStartX; i < _nBlockStartX + 15; i++) {
                    if (_bvBlockMask[j - _nBlockStartY][i - _nBlockStartX] == True) {
                        BuildActiveBlockGeometry(pTerrainBlockList, i, j, _pvVertexList, _pvIndexList);
                    }
                }
            }
        }
    }else if ( nShape == 1 ) {
        for( int32 j = nBlockCoordsY - (nSize - 1); j < nBlockCoordsY + nSize; j++ ){
            for( int32 i = nBlockCoordsX - (nSize - 1); i < nBlockCoordsX + nSize; i++ ){
                BuildActiveBlockGeometry( pTerrainBlockList, i, j, _pvVertexList, _pvIndexList );
            }
        }
    }
    if (m_rRenderBuffer.IsAttached()) {
        m_rRenderBuffer->UpdateBuffer(_vVertex.data(), _vVertex.size());
    }else {
        m_rRenderBuffer = NEW CVertexBuffer( EVT_VECTOR_COLOR_TEXCOORDS, _vVertex.data(), _vVertex.size(), True);
    }

    if (m_rIndexBuffer.IsAttached()) {
        m_rIndexBuffer->UpdateBuffer(_vIndexData.data(), _vIndexData.size());
    }else {
        m_rIndexBuffer = NEW CIndexBuffer(_vIndexData.data(), _vIndexData.size(), True, sizeof(uint16));
    }
}




////////////////////////////////////////////////////////////////////////////////////////////////////
CTerrainActiveBlockHelperObject::CTerrainActiveBlockHelperObject() {
    m_nBlockCoordsX = -1;
    m_nBlockCoordsY = -1;
    m_nBrushSize = -1;
    m_nBrushShapeType = 0;
}
CTerrainActiveBlockHelperObject::~CTerrainActiveBlockHelperObject() {

}
void CTerrainActiveBlockHelperObject::Init(CTerrainObject* pTerrainObject, int32 nBrushType, int32 nBrushSize) {
    m_pTerrainObject = pTerrainObject;
    m_nBrushSize = nBrushSize;
    m_nBrushShapeType = nBrushType;
    m_nBlockCoordsX = 1;
    m_nBlockCoordsY = 1;
    m_vActiveBlockList.clear();
    m_rTerrainHelperGeometry = NEW CTerrainBrushGeometry( m_pTerrainObject );
    m_rTerrainHelperGeometry->UpdateGeometry(&m_vActiveBlockList, m_nBlockCoordsX, m_nBlockCoordsY, m_nBrushShapeType, m_nBrushSize);

    m_rRenderItem = NEW CRenderItem( m_vWorldM );
    m_rRenderItem->m_eRenderType = 0;
    m_rRenderItem->m_bDepthWrite = False;
    m_rRenderItem->m_bDepthTest = False;
    m_rRenderItem->m_bCastShadow = False;
    m_rRenderItem->m_bReceiveShadow = False;
    m_rRenderItem->m_bFogEnable = False;
    m_rRenderItem->m_bLightEnable = False;
    m_rRenderItem->m_bLineMode = False;
    m_rRenderItem->m_eBlending = NormalBlending;
    m_rRenderItem->SetPrimitiveType( EPT_TRIANGLE_LIST );

    CTexture* _pTexture = RESOURCE_GETTEXTURE("UV_Grid_Sm.jpg");
    m_rRenderItem->CreateNormalDiffuseBatchData( _pTexture, m_rTerrainHelperGeometry->GetRenderBuffer(), m_rTerrainHelperGeometry->GetIndexBuffer());
}
int32 CTerrainActiveBlockHelperObject::GetRenderElementHandles(CRenderElement** vRenderElementHandle, int32 nMaxCount) {
    vRenderElementHandle[0] = m_rRenderItem->m_pRenderElement.GetEntityData();
    return 1;
}
list<CTerrainBlock*>* CTerrainActiveBlockHelperObject::UpdateActiveBlock( int32 nBlockCoordsX, int32 nBlockCoordsY, int32 nSize, bool32 bForceUpdate){
    list<CTerrainBlock*>* _pActiveBlockList = &m_vActiveBlockList;
    if( (bForceUpdate == False) && ( m_nBlockCoordsX == nBlockCoordsX && m_nBlockCoordsY == nBlockCoordsY && m_nBrushSize == nSize ) ){
        return _pActiveBlockList;
    }

    m_nBlockCoordsX = nBlockCoordsX;
    m_nBlockCoordsY = nBlockCoordsY;
    m_nBrushSize = nSize;

    m_vActiveBlockList.clear();
    m_rTerrainHelperGeometry->UpdateGeometry( &m_vActiveBlockList, nBlockCoordsX, nBlockCoordsY, m_nBrushShapeType, nSize );
    return _pActiveBlockList;
}
void CTerrainActiveBlockHelperObject::SetBrushInfo( int32 nBrushType, int32 nBrushSize ){
    if(m_nBrushShapeType != nBrushType || m_nBrushSize != nBrushSize){
        m_nBrushSize = nBrushSize;
        m_nBrushShapeType = nBrushType;
        m_rTerrainHelperGeometry->UpdateGeometry(&m_vActiveBlockList, m_nBlockCoordsX, m_nBlockCoordsY, m_nBrushShapeType, m_nBrushSize);
    }
}